【UEFI实战】UEFI用户交互界面基础说明

您所在的位置:网站首页 boot manager menu 【UEFI实战】UEFI用户交互界面基础说明

【UEFI实战】UEFI用户交互界面基础说明

2023-09-30 07:10| 来源: 网络整理| 查看: 265

前言

本文以vUDK2017: https://github.com/tianocore/edk2.git Tag vUDK2017.中的代码为例说明UEFI用户交互界面的实现。

这里UEFI用户交互界面的实现载体是OVMF(使用QEMU启动),其形式如下:

它一般被叫做Front Page(后面将以该名称来称呼上述的界面),其下还包括Setup,Boot Manager,Device Manager等选项。

相比Legacy BIOS,UEFI的交互界面要丰富得多,比如支持多语言,支持图片等,不过EDK默认带的还是最原始的,跟Legacy BIOS类似的界面。

本文讨论的就是该界面的实现。

启动

在EDK2017的OVMF代码中,Front Page被做成一个独立的APP(跟Shell一样),然后注册,可以通过在启动过程中按F2来进入,具体的注册代码如下:

VOID PlatformRegisterOptionsAndKeys ( VOID ) { EFI_STATUS Status; EFI_INPUT_KEY Enter; EFI_INPUT_KEY F2; EFI_INPUT_KEY Esc; EFI_BOOT_MANAGER_LOAD_OPTION BootOption; // // Register ENTER as CONTINUE key // Enter.ScanCode = SCAN_NULL; Enter.UnicodeChar = CHAR_CARRIAGE_RETURN; Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL); ASSERT_EFI_ERROR (Status); // // Map F2 to Boot Manager Menu // F2.ScanCode = SCAN_F2; F2.UnicodeChar = CHAR_NULL; Esc.ScanCode = SCAN_ESC; Esc.UnicodeChar = CHAR_NULL; Status = EfiBootManagerGetBootManagerMenu (&BootOption); ASSERT_EFI_ERROR (Status); Status = EfiBootManagerAddKeyOptionVariable ( NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL ); ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED); Status = EfiBootManagerAddKeyOptionVariable ( NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL ); ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED); }

而Front Page对应APP的驱动是UiApp.inf,它对应的GUID是:

# Point to the MdeModulePkg/Application/UiApp/UiApp.inf gEfiMdeModulePkgTokenSpaceGuid.PcdBootManagerMenuFile|{ 0x21, 0xaa, 0x2c, 0x46, 0x14, 0x76, 0x03, 0x45, 0x83, 0x6e, 0x8a, 0xb6, 0xf4, 0x66, 0x23, 0x31 }

在EfiBootManagerGetBootManagerMenu()函数中会根据上述的GUID寻找UiApp模块,并生成对应的启动项。

最终的结果就是启动过程中按F2就可以进入UiApp模块,其入口是InitializeUserInterface(),将在后续的内容中介绍。

UiApp模块

InitializeUserInterface()模块的大致流程如下:

其中绿色部分涉及到交互相关的操作,后续会重点说明。

字体

字体使用一种称为Glyph的元素表示,它其实就是一个二进制的文件,里面包含了描述字体的元素,但是具体是怎么样表示的,目前还不是很清楚,这个也不是我们需要关注的重点。

这个二进制在代码中有下述的数组表示:

typedef struct { /// /// This 4-bytes total array length is required by HiiAddPackages() /// UINT32 Length; // // This is the Font package definition // EFI_HII_PACKAGE_HEADER Header; UINT16 NumberOfNarrowGlyphs; UINT16 NumberOfWideGlyphs; EFI_NARROW_GLYPH NarrowArray[NARROW_GLYPH_NUMBER]; EFI_WIDE_GLYPH WideArray[WIDE_GLYPH_NUMBER]; } FONT_PACK_BIN; FONT_PACK_BIN mFontBin = { sizeof (FONT_PACK_BIN), { sizeof (FONT_PACK_BIN) - sizeof (UINT32), EFI_HII_PACKAGE_SIMPLE_FONTS, }, NARROW_GLYPH_NUMBER, 0, { // Narrow Glyphs { 0x05d0, 0x00, { 0x00, // 后面的省略

这个数组通过一个通过HiiAddPackages()导入,如下所示:

/** Routine to export glyphs to the HII database. This is in addition to whatever is defined in the Graphics Console driver. **/ EFI_HII_HANDLE ExportFonts ( VOID ) { return HiiAddPackages ( &mFontPackageGuid, gImageHandle, &mFontBin, NULL ); } 字符串

字符串通过UNI文件转换成,编译时在AutoGen.c中生成对应的数组,然后通过下面的函数来注册到HII数据库中:

/** Initialize HII global accessor for string support. **/ VOID InitializeStringSupport ( VOID ) { gStringPackHandle = HiiAddPackages ( &mUiStringPackGuid, gImageHandle, UiAppStrings, NULL ); ASSERT (gStringPackHandle != NULL); }

这里的UiAppStrings就是通过.uni文件生成的字符串表示。

可以看到,导入字体和字符串使用的是相同的函数。

UI Entry

进入UI界面是通过UiEntry()来实现的,其大致流程如下:

这里的重点也主要在绿色部分,它包含了Front Page的初始化和调用。

上述的绿色部分大致流程如下所示:

这里最重要的是两个部分,一个是更新Front Page的部分,另一个是SendForm()的部分。

更新Front Page部分主要由UpdateFrontPageBannerStrings()、UpdateFrontPageForm()等函数组成,它们使用了各类HII操作来更新界面,比如说UiCustomizeFrontPageBanner()构成了Front Page界面中的一条条的字符串显示(就是开头图片中的蓝字部分),另外还有UiCustomizeFrontPage()、HiiUpdateForm()等函数,都更新了界面。

SendForm()部分,它其实是整个UEFI界面显示的引擎,这部分实现在显示界面(比如图形输出界面,或者串口)上显示前面更新的内容,后续会详细介绍。

本文只是简单的介绍,以上。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3